from __future__ import absolute_import, division

from gui.panda.base import *
  

class CameraController(Object):
    display      = Attribute()
    distance     = Attribute()
    hover        = Attribute()
    main_angle   = Attribute()
    
    fov_min      = Attribute(initial = 10)
    fov_max      = Attribute(initial = 70)
    
    angle_min    = Attribute(initial =  1)
    angle_max    = Attribute(initial = 90)
    
    fov_default  = Attribute(initial = 50)
    fov_change   = Attribute(initial =  5)
    angle_change = Attribute(initial =  5)
    
    target       = Attribute(writable = True, changed = lambda self: self.recalculate())
    angle        = Attribute(writable = True, changed = lambda self: self.recalculate(),         clamp = (angle_min, angle_max))
    fov          = Attribute(writable = True, changed = lambda self: self.lens.setFov(self.fov), clamp = (fov_min,   fov_max))
    
    def setup(self):
        self.angle = self.main_angle
        self.fov   = self.fov_default
    
    @property
    def camera(self):
        return self.display.getCamera()
    
    @property
    def lens(self):
        return self.camera.node().getLens(self.display.getLensIndex())
    
    def center_on_tile(self, point):
        if point is None:
            return
        
        self.target = (int(point.x) + 0.5, int(point.y) + 0.5, self.hover)
    
    def zoom_in(self):
        if self.angle > self.main_angle or self.fov <= self.fov_min:
            self.angle -= self.angle_change
            
            if self.angle < self.main_angle and self.fov > self.fov_min:
                self.angle = self.main_angle
        else:
            self.fov -= self.fov_change
        
        self.force_aspect()
    
    def zoom_out(self):
        if self.angle < self.main_angle or self.fov >= self.fov_max:
            self.angle += self.angle_change
            
            if self.angle > self.main_angle and self.fov < self.fov_max:
                self.angle = self.main_angle
        else:
            self.fov += self.fov_change
        
        self.force_aspect()
    
    def recalculate(self):
        if self.target is None or self.angle is None:
            return
        
        dy = -self.distance * math.cos(self.angle * math.pi / 180.0)
        dz =  self.distance * math.sin(self.angle * math.pi / 180.0)
        
        self.camera.setPos(Vec3  (*self.target) + Vec3(0, dy, dz))
        self.camera.lookAt(Point3(*self.target))
        
        self.force_aspect()
    
    def force_aspect(self):
        self.lens.setAspectRatio(self.display.getPixelWidth() / self.display.getPixelHeight())
